#pragma once
#include<stdint.h>
#include"fftr.h"

typedef enum WIN_TYPE{
	HANNING, SINE, HAMMING, POVEY, RECTANGULAR, BLACKMAN
}wintype;
typedef uint8_t BOOL;


//注意分隔两块结构体成员, 第一块是用户可以设置的参数, 第二块需要在第一块数据设置完成之后进行计算
typedef struct FBANK {
	int16_t num_mel_bins;           // 梅尔三角滤波器个数
	int16_t sample_frequency;       // 采样率
	float frame_length;             // ms为单位的帧长, 默认值25
	float frame_shift;              // ms为单位的帧移, 默认值10

	float blackman_coeff;           // blackman窗的可选参数, 当window_type不是blackman时, 该参数无意义, 默认0.42
	wintype window_type;            // 窗类型, 目前支持的窗类型见`enum WIN_TYPE`, 默认povey
	float preemphasis_coefficient;  // 预加重系数, 如果=0, 不使用预加重
	BOOL remove_dc_offset;          // 是否对每一帧数据加窗和预加重之前先去除直流分量，默认1

	BOOL use_energy;                // 是否在输出的fbank特征的基础上增加一个对数能量特征. 默认0
	float energy_floor;             // 能量的下限, 当use_energy为1时计算能量设置的下限, use_energy=0时, 无意义. 默认0
	BOOL htk_compat;                // 对数能量特征增加在fbank特征的前面还是后面, 等于1添加在后面, 等于0添加在前面. use_energy=0时, 无意义
	BOOL raw_energy;                // 如果为1, 在预加重和加窗之前计算能量, 否则在之后计算. 默认1. use_energy=0时, 无意义

	int16_t fbank_bins;             // 最终输出的特征数量, 当use_energy=0时候, 和num_mel_bins, use_energy=1时, 等于num_mel_bins+1, 增加的1就是前面的对数能量特征
	BOOL use_log_fbank;             // 是否对梅尔谱应用对数运算, 默认1
	BOOL use_power;                 // 梅尔谱是否应用能量谱计算, 默认1
	BOOL round_to_power_of_two;	    // 是否给帧长扩充到最近的2的整数幂, 以应用更高效的fft, 默认1
	BOOL subtract_mean;             // 是否在计算多个fbank之后, 对每个特征减去均值. 默认0. 这个参数只有使用FbankProcess_block函数有效
	float low_freq;                 // 梅尔窗的最低截止频率，默认20
	float high_freq;                // 梅尔窗的最高截止频率。默认0 (小于等于0的不合理值，会被调整为奈奎斯特频率)

	//  -------------------------------------------------------------------------------------------------------------------------------------------------------------

	float* window;                  // 存放计算好的窗函数数据
	int16_t window_size;            // 窗的长度，和帧长一致
	int16_t padded_window_size;     // 扩充的窗长，如果round_to_power_of_two=1. 它是窗长的下一个2的整数幂，否则它等于window_size
	float** melbins;                // 存放所有三角mel窗的meil系数，具体的存储方案，见readme
	int16_t* bin_start;             // 存放每个三角窗在频谱上的起点
	int16_t* bin_len;               // 存放每个三角窗的长度

	float* table_td;                // 临时存放时域数据
	fftobj fft;                     // kiss fft的结构体
	fft_cpx* table_fd;              // 临时存放频域数据

	// 下列是kaldi的fbank目前不支持修改的参数
	// float vtln_high;
	// float vtln_low;
	// float vtln_warp;
	// int16_t channel;
	// float dither;
	// bool snip_edges;
	// float min_duration;
}fbank;

// 初始化一个基础的fbank结构体指针，大部分参数都初始化成默认值。后面可以在结构体上直接更改
fbank* FbankInit(uint16_t num_mel_bins, int16_t sample_frequency);
// 将设置的参数进行注册，计算好诸如窗还有mel滤波器组之类的参数，注册之后不再能更改参数
void FbankRegister(fbank* inst);
// 输入一帧数据输出fbank特征
void FbankProcess(fbank* inst, float* frame_in, float* fbank_out);
// 输入长时域信号，以及帧的数量，输出顺序排列的多帧的特征
void FbankProcess_block(fbank* inst, float* wav_in, float* out, int16_t block_num);
// 释放结构
void FbankFree(fbank* inst);